package com.inspur.edp.web.formmetadata.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.web.common.metadata.MetadataUtility;
import com.inspur.edp.web.formmetadata.api.SmartFormService;
import com.inspur.edp.web.formmetadata.api.entity.SmartFormContent;
import com.inspur.edp.web.formmetadata.api.entity.SmartFormEntity;
import com.inspur.edp.web.formmetadata.api.entity.SmartFormField;
import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent;
import io.swagger.util.Json;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 为智能填单提取表单属性
 */
public class SmartFormServiceImpl implements SmartFormService {

    // 子级控件的属性
    private static final List<String> childPropertyNamesForAngular = Arrays.asList("contents", "fields");
    private static final List<String> childPropertyNamesForVue = Arrays.asList("contents", "columns");

    public SmartFormServiceImpl() {
    }

    @Override
    public SmartFormContent getFormContent(String formId) {
        GspMetadata formMetadata = MetadataUtility.getInstance().getMetadataWithRuntime(formId);
        if (formMetadata == null) {
            return null;
        }

        boolean isVueForm = false;
        if(formMetadata.getProperties() != null && formMetadata.getProperties().getFramework() != null) {
            String frameworkType = String.valueOf(formMetadata.getProperties().getFramework());
            isVueForm = "Vue".equals(frameworkType);
        }

        FormMetadataContent formContents = (FormMetadataContent) formMetadata.getContent();
        if(formContents == null) {
            return null;
        }
        JsonNode formContent = formContents.getContents();
        if(formContent == null){
            return null;
        }
        MetadataHeader header = formMetadata.getHeader();
        SmartFormContent smartFormContent = new SmartFormContent();
        smartFormContent.setEntity(extract(formContent, isVueForm));
        smartFormContent.setId(header.getId());
        smartFormContent.setCode(header.getCode());
        smartFormContent.setName(header.getName());

        JsonNode entity = isVueForm ? formContent.at("/module/entity/0") : formContent.at("/module/schemas/0");
        if(entity != null){
            smartFormContent.setVoId(getStringValue(entity, "/id"));
        }

        return smartFormContent;

    }

    public SmartFormEntity extract(JsonNode formContent, boolean isVueForm){
        // 1、提取viewmodel中的字段
        JsonNode viewModels = formContent.at("/module/viewmodels");
        List<String> fieldIds = extractViewModels(viewModels);

        // 2、获取component中字段信息
        JsonNode components = formContent.at("/module/components");
        Map<String, SmartFormField> fieldMap = extractComponents(components, fieldIds, isVueForm);

        // 3、构建实体树
        JsonNode mainEntity = isVueForm ? formContent.at("/module/entity/0/entities/0") : formContent.at("/module/schemas/0/entities/0");

        SmartFormEntity smartFormEntity = extractEntities(mainEntity, fieldMap);

        return smartFormEntity;
    }

    /**
     * 提取视图模型中的字段
     * @param viewModels
     * @return
     */
    private List<String> extractViewModels(JsonNode viewModels){
        List<String> fieldIds = new ArrayList<>();
        if(viewModels == null || viewModels.isEmpty()){
            return fieldIds;
        }
        for(JsonNode viewModel : viewModels){
            JsonNode fields = viewModel.get("fields");
            if (fields != null && !fields.isEmpty()) {
                fieldIds.addAll(fields.findValuesAsText("id"));
            }
        }

        return fieldIds;
    }


    /**
     * 提取组件中的字段
     * @param components
     * @param fieldIds
     * @return
     */
    private Map<String, SmartFormField> extractComponents(JsonNode components, List<String> fieldIds, boolean isVueForm) {
        Map<String, SmartFormField> fieldMap = new HashMap<>();
        if(components == null || components.isEmpty()){
            return fieldMap;
        }

        for(JsonNode component : components){
            // 提取当前控件
            Map<String, SmartFormField> currentFieldMap = extractComponent(fieldIds, component, isVueForm);
            fieldMap.putAll(currentFieldMap);

            // 提取子控件
            List<String> childPropertyNames = isVueForm ? childPropertyNamesForVue : childPropertyNamesForAngular;
            for (String childPropertyName : childPropertyNames){
                JsonNode childComponent = component.get(childPropertyName);
                if (childComponent != null && !childComponent.isEmpty() && childComponent.isArray()) {
                    Map<String, SmartFormField> childFieldMap = extractComponents(childComponent, fieldIds, isVueForm);
                    fieldMap.putAll(childFieldMap);
                }
            }
        }
        return fieldMap;
    }

    /**
     * 提取控件的属性
     * @param fieldIds
     * @param component
     */
    private Map<String, SmartFormField> extractComponent(List<String> fieldIds, JsonNode component, boolean isVueForm) {
        Map<String, SmartFormField> fieldMap = new HashMap<>();
        if(component == null || component.isEmpty()){
            return fieldMap;
        }
        JsonNode fieldId = component.at("/binding/field");
        JsonNode type = component.at("/type");
        if (fieldId == null || type == null || type.isMissingNode() || fieldId.isMissingNode()) {
            return fieldMap;
        }

        String fieldIdText = fieldId.asText();
        if (fieldIds.contains(fieldIdText)) {
            // todo 提取属性

            SmartFormField field = new SmartFormField();
            field.setId(fieldIdText);

            field.setName(getStringValue(component, isVueForm ? "/label" : "/title"));


            Map<String, Object> properties = field.getProperties();
            if(isVueForm){
                this.extractPropertiesForVue(component, properties);
            }else{
                this.extractPropertiesForAngular(component, properties);
            }

            field.setProperties(properties);
            fieldMap.put(fieldIdText, field);
        }
        return fieldMap;
    }

    private void extractPropertiesForVue(JsonNode component, Map<String, Object> properties){
        properties.put("required", getBooleanValue(component,"/editor/required"));
        properties.put("multiSelect", getBooleanValue(component,"/editor/multiSelect"));
        properties.put("helpId", getStringValue(component,"/editor/helpId"));
        properties.put("precision", getNumberValue(component,"/editor/precision"));

        String dataSourceType = getStringValue(component, "/editor/dataSourceType");
        if(!"dynamic".equals(dataSourceType)){
            properties.put("enumData", getObjectValue(component, "/editor/data"));
        }
    }

    private void extractPropertiesForAngular(JsonNode component, Map<String, Object> properties){
        JsonNode editor = component.at("/editor");
        JsonNode extractedComponent = (editor != null && !editor.isMissingNode()) ? editor : component;

        properties.put("required", getBooleanValue(extractedComponent,"/require"));
        properties.put("multiSelect", getBooleanValue(extractedComponent,"/multiSelect"));
        properties.put("helpId", getStringValue(extractedComponent,"/helpId"));
        properties.put("precision", getNumberValue(extractedComponent,"/precision"));

        String dataSourceType = getStringValue(extractedComponent, "/dataSourceType");
        if(!"dynamic".equals(dataSourceType)){
            properties.put("enumData", getObjectValue(extractedComponent, "/enumData"));
            if(properties.get("enumData") == null){
                properties.put("enumData", getObjectValue(extractedComponent, "/items"));
            }
        }
    }


    /**
     * 提取实体树
     * @param entityNode
     * @param fieldMap
     * @return
     */
    private SmartFormEntity extractEntities(JsonNode entityNode, Map<String, SmartFormField> fieldMap) {
        SmartFormEntity smartFormEntity = new SmartFormEntity();
        if (entityNode == null || entityNode.isEmpty()) {
            return smartFormEntity;
        }

        // 提取主表
        smartFormEntity.setId(getStringValue(entityNode, "/id"));
        smartFormEntity.setCode(getStringValue(entityNode, "/code"));
        smartFormEntity.setName(getStringValue(entityNode, "/name"));

        // 提取主表字段
        JsonNode fieldNodes = entityNode.at("/type/fields");
        List<SmartFormField> smartFormFields = extractFields(fieldNodes, fieldMap);
        smartFormEntity.setFields(smartFormFields);

        // 提取子表
        JsonNode childEntityNodes = entityNode.at("/type/entities");
        if (childEntityNodes == null || childEntityNodes.isEmpty()) {
            return smartFormEntity;
        }

        for(JsonNode childEntityNode : childEntityNodes){
            SmartFormEntity childEntity = extractEntities(childEntityNode, fieldMap);
            // 如果当前子对象有字段，则添加
            if (!childEntity.getFields().isEmpty()) {
                smartFormEntity.getChildEntities().add(childEntity);
            }
        }

        return smartFormEntity;
    }

    private List<SmartFormField> extractFields(JsonNode fieldNodes, Map<String, SmartFormField> fieldMap) {
        List<SmartFormField> smartFormFields = new ArrayList<>();
        if(fieldNodes == null || fieldNodes.isEmpty()){
            return smartFormFields;
        }
        for(JsonNode fieldNode : fieldNodes){
            // 提取当前字段
            // todo 提取属性
            String id = getStringValue(fieldNode, "/id");
            SmartFormField smartFormField = fieldMap.get(id);
            if(smartFormField != null){
                this.setFormField(smartFormField, fieldNode, true);
                smartFormFields.add(smartFormField);
                continue;
            }

            // 提取子字段
            JsonNode childFieldNodes = fieldNode.at("/type/fields");
            if (childFieldNodes == null || childFieldNodes.isEmpty()) {
                continue;
            }

            List<SmartFormField> childFields = extractFields(childFieldNodes, fieldMap);
            if (childFields.isEmpty()) {
                continue;
            }
            smartFormField = new SmartFormField();
            this.setFormField(smartFormField, fieldNode, false);
            smartFormField.setName(getStringValue(fieldNode, "/name"));

            // formField.setDataType(getStringValue(fieldNode, "/type/$type"));

            smartFormField.setChildFields(childFields);
            smartFormFields.add(smartFormField);
        }

        return smartFormFields;
    }

    private void setFormField(SmartFormField smartFormField, JsonNode fieldNode, boolean isSetDataType){
        smartFormField.setId(getStringValue(fieldNode, "/id"));
        smartFormField.setCode(getStringValue(fieldNode, "/code"));
        smartFormField.setOriginalId(getStringValue(fieldNode, "/originalId"));
        if(isSetDataType){
            smartFormField.setDataType(getStringValue(fieldNode, "/type/$type"));
            if("EnumType".equals(smartFormField.getDataType())){
                smartFormField.setDataType(getStringValue(fieldNode, "/type/valueType/$type"));
            }
        }
        smartFormField.getProperties().put("defaultValue", getStringValue(fieldNode, "/defaultValue"));
    }

    private String getStringValue(JsonNode node, String key){
        if(node == null || node.isEmpty()){
            return null;
        }
        JsonNode result = node.at(key);
        if(result == null || StringUtils.isEmpty(result.asText())){
            return null;
        }
        return result.asText();
    }

    private Integer getNumberValue(JsonNode node, String key){
        if(node == null || node.isEmpty()){
            return null;
        }
        JsonNode result = node.at(key);
        if(result == null || !result.isNumber()){
            return null;
        }
        return result.asInt();
    }

    private Boolean getBooleanValue(JsonNode node, String key){
        if(node == null || node.isEmpty()){
            return null;
        }
        JsonNode result = node.at(key);
        if(result == null || !result.isBoolean()){
            return null;
        }
        return result.asBoolean();

    }

    private Object getObjectValue(JsonNode node, String key){
        if(node == null || node.isEmpty()){
            return null;
        }
        JsonNode result = node.at(key);
        if(result == null || result.isEmpty()){
            return null;
        }
        return result;
    }

}
